// src/composables/form/useForm.ts
import { ref, reactive, nextTick, toRaw } from "vue";
import { message } from "@/utils/message";

interface FormOptions {
  resetAfterSubmit?: boolean;
  showSuccessMessages?: boolean;
  showErrorMessages?: boolean;
}

interface FetchDetailOptions<TForm extends object> {
  dataMapping?: (data: any) => Partial<TForm>;
  responseAdapter?: (response: any) => any;
  errorMessage?: string;
  cleanUnmatchedFields?: boolean;
  updateInitialSnapshot?: boolean;
}

// 定义通用的 ID 类型
type IdType = string | number;

const deepClone = <T>(value: T): T => {
  if (value === undefined) {
    return value;
  }
  if (typeof structuredClone === "function") {
    return structuredClone(value);
  }
  const serialized = JSON.stringify(value);
  return serialized ? (JSON.parse(serialized) as T) : value;
};

const parseDetailOptions = <TForm extends object>(
  options?: FetchDetailOptions<TForm> | ((data: any) => Partial<TForm>)
): FetchDetailOptions<TForm> => {
  if (typeof options === "function") {
    return { dataMapping: options };
  }
  return options ?? {};
};

export function useForm<T extends object>(
  initialData: T,
  options: FormOptions = {}
) {
  const {
    resetAfterSubmit = true,
    showSuccessMessages = true,
    showErrorMessages = true
  } = options;

  const formRef = ref();
  const formLoading = ref(false);
  const formData = reactive<T>(deepClone(initialData));

  let initialSnapshot = deepClone(initialData);

  const assignToForm = (source: Partial<T>, cleanUnmatchedFields = false) => {
    if (cleanUnmatchedFields) {
      Object.keys(formData).forEach(key => {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          const value = (source as any)[key];
          (formData as any)[key] =
            value && typeof value === "object" ? deepClone(value) : value;
        } else if (Object.prototype.hasOwnProperty.call(initialSnapshot, key)) {
          const initialValue = (initialSnapshot as any)[key];
          (formData as any)[key] =
            initialValue && typeof initialValue === "object"
              ? deepClone(initialValue)
              : initialValue;
        } else {
          (formData as any)[key] = undefined;
        }
      });
      return;
    }

    Object.keys(source).forEach(key => {
      if (key in formData) {
        const value = (source as any)[key];
        (formData as any)[key] =
          value && typeof value === "object" ? deepClone(value) : value;
      }
    });
  };

  const captureSnapshot = () => {
    initialSnapshot = deepClone(toRaw(formData) as T);
  };

  // 重置表单
  const resetForm = () => {
    assignToForm(deepClone(initialSnapshot), true);
    formRef.value?.resetFields?.();
    formRef.value?.clearValidate?.();
  };

  const resetFormAsync = async () => {
    resetForm();
    await nextTick();
  };

  // 通用提交方法
  const handleSubmit = async (
    submitFn: () => Promise<any>,
    successMessage: string = "操作成功",
    errorMessage: string = "操作失败"
  ) => {
    const formInstance = formRef.value;
    if (!formInstance) return false;

    try {
      const validateResult = await formInstance.validate?.();
      if (validateResult === false) return false;

      formLoading.value = true;
      await submitFn();

      if (showSuccessMessages) {
        message(successMessage, { type: "success" });
      }

      if (resetAfterSubmit) {
        resetForm();
      }

      return true;
    } catch (error: any) {
      if (showErrorMessages) {
        message(error?.message || errorMessage, { type: "error" });
      }
      console.error(`${errorMessage}:`, error);
      return false;
    } finally {
      formLoading.value = false;
    }
  };

  // 通用获取详情方法
  const fetchDetail = async (
    fetchFn: (id: IdType) => Promise<any>,
    id: IdType,
    config?: FetchDetailOptions<T> | ((data: any) => Partial<T>)
  ) => {
    if (id === undefined || id === null || id === "") {
      return;
    }

    const {
      dataMapping,
      responseAdapter = (response: any) => response?.data ?? response,
      errorMessage = "获取详情失败",
      cleanUnmatchedFields = false,
      updateInitialSnapshot = false
    } = parseDetailOptions<T>(config);

    try {
      formLoading.value = true;
      const response = await fetchFn(id);
      const data = responseAdapter(response);
      const mappedData = dataMapping ? dataMapping(data) : data;

      if (mappedData && typeof mappedData === "object") {
        assignToForm(mappedData as Partial<T>, cleanUnmatchedFields);
      }

      if (updateInitialSnapshot) {
        captureSnapshot();
      }

      return data;
    } catch (error: any) {
      if (showErrorMessages) {
        message(error?.message || errorMessage, { type: "error" });
      }
      console.error(`${errorMessage}:`, error);
      throw error;
    } finally {
      formLoading.value = false;
    }
  };

  return {
    formRef,
    formLoading,
    formData,
    resetForm,
    resetFormAsync,
    handleSubmit,
    fetchDetail
  };
}
